with Ada.Strings.Wide_Fixed;
with Ada.Calendar;

with GWindows;
with GWindows.GStrings;
with GWindows.Message_Boxes;
with GWindows.Drawing_Objects;

with export;
with Time;

package body GUI is

  procedure Set_Font (Window : in out GWindows.Base.Base_Window_Type'Class) is
    use GWindows.Base;
    Window_Font : GWindows.Drawing_Objects.Font_Type;
  begin
    --  Use Standard Windows GUI font instead of system font
    GWindows.Drawing_Objects.Create_Stock_Font
    (Window_Font,
     GWindows.Drawing_Objects.Default_GUI);
    Set_Font (window, Window_Font);
  end Set_Font;

  function to_boolean (check_state : in check_state_type) return boolean is
  begin
    return check_state = Checked;
  end to_boolean;

  procedure create_window (window : in out FFXIAlarm_Window_Type) is

    procedure Create_Main_Window (Window : in out FFXIAlarm_Window_Type) is
      use GWindows.Base;
    begin
      Create_Unresizeable (window.Top_Window,
                           "FFXI Alarm "&GUI_Strings.Version,
                           Width => 330, Height => 195);
      Small_Icon (window.Top_Window, Resources.Small_Icon);
      Large_Icon (window.Top_Window, Resources.Large_Icon);
      Set_Font(Window.Top_Window);

      Create_as_Control (window.Window, window.Top_Window, "", 0, 0, 0, 0);
      Dock(window.Window, Fill);

      Create (window.startstop, window.window, "&Start",
              5, 5, 135, 25);
      Create (window.ViewLog, window.window, "Event Log",
              145, 5, 95, 25);

      Create (window.Tell_chk, window.window, GUI_Strings.Tell,
              15, 35, 60, 20);
      State (window.Tell_chk, Checked);

      Create (window.LS_chk, window.window, GUI_Strings.Linkshell,
              75, 35, 60, 20);
      State (window.LS_chk, Unchecked);

      Create (window.Party_chk, window.window, GUI_Strings.Party,
              135, 35, 60, 20);
      State (window.Party_chk, Unchecked);

      Create (window.Say_chk, window.window, GUI_Strings.Say,
              195, 35, 60, 20);
      State (window.Say_chk, Unchecked);

      Create (window.Shout_chk, window.window, GUI_Strings.Shout,
              255, 35, 60, 20);
      State (window.Shout_chk, Unchecked);

      Create (window.Loop_chk, window.window, GUI_Strings.Loop_lbl,
              255, 5, 60, 20);
      State (window.Loop_chk, Checked);

      Create (window.Key, window.window,
              "Keywords (not case sensitive, separate words with semicolons)",
              5, 60, 312, 77);
      Create_as_control (window.Key_Pan, window.Key, "", 5, 17,
                         Client_Area_Width(window.Key)-7,
                         Client_Area_Height(window.Key)-19);
      --Dock(window.Key_Pan, Fill);
      Create (window.Tab_Control, window.Key_Pan, 0, 0,
              Client_Area_Width(window.Key_Pan)-3,
              Client_Area_Height(window.Key_Pan)-3);
      --Create (window.Key_chk, window.Key_Pan, "Enable", 240, 1, 60, 20);
      --Create (window.Key_Edit, window.Key_Pan, "", 0, 0, 234, 21);

      for i in Window.Key_Alarms'Range loop
        Insert_Tab (Window.Tab_Control, i-1,
                    "Alarm"&GWindows.GStrings.To_GString_from_String(Integer'Image(i)));
        Create_As_Control (Window.Key_Alarms(i).Alarm, Window.Tab_Control, "",
                           0, 0, 0, 0, Show => False);
        Tab_Window (Window.Tab_Control, i-1, Window.Key_Alarms(i).Alarm'Unchecked_Access);
        Create (window.Key_Alarms(i).Chk, window.Key_Alarms(i).Alarm, "Enable", 240, 6, 60, 20);
        Create (window.Key_Alarms(i).Edit, window.Key_Alarms(i).Alarm, "", 5, 5, 234, 21);
        Text_Limit(window.Key_Alarms(i).Edit, 50);
        State (window.Key_Alarms(i).Chk, Unchecked);
      end loop;

      Create (window.status, window.Top_Window, "Idle");
      Dock(window.status, At_Bottom);

      Dock_Children (window.Top_Window);

      Window.Menu := Create_Popup;
      Append_Item (Window.Menu,
                   GUI_Strings.Tell,
                   Menu_Commands.MC_TELL);
      Append_Item (Window.Menu,
                   GUI_Strings.Linkshell,
                   Menu_Commands.MC_LINKSHELL);
      Append_Item (Window.Menu,
                   GUI_Strings.Party,
                   Menu_Commands.MC_PARTY);
      Append_Item (Window.Menu,
                   GUI_Strings.Say,
                   Menu_Commands.MC_SAY);
      Append_Item (Window.Menu,
                   GUI_Strings.Shout,
                   Menu_Commands.MC_SHOUT);
      Append_Separator (Window.Menu);
      Append_Item (Window.Menu,
                   GUI_Strings.Loop_lbl,
                   Menu_Commands.MC_LOOP);
      Append_Item (Window.Menu,
                   GUI_Strings.Start,
                   Menu_Commands.MC_START);
      Append_Separator (Window.Menu);
      Append_Item (Window.Menu, "Close", Menu_Commands.MC_CLOSE);

    end Create_Main_Window;

  begin
    Create_Main_Window(window);
    Show (window.Top_window);
  end create_window;

  procedure Close_Window (window : in out FFXIAlarm_Window_Type) is
  begin
    Tray_Icon(Window.Top_Window,
              Resources.Small_Icon,
              Display => False);
    Close(Window.Top_Window);
  end Close_Window;

  procedure Enable (Window  : in out FFXIAlarm_Window_Type;
                    Enabled : in Boolean) is
  begin
    if Enabled then
      Enable(Window.Window);
    else
      Disable(Window.Window);
    end if;
  end Enable;

  procedure set_status(window : in out FFXIAlarm_Window_Type;
                       msg : in GWindows.GString) is
  begin
    Text(window.status, msg);
  end set_status;

  procedure Notify(window : in out FFXIAlarm_Window_Type;
                   notify : in GWindows.GString) is
    use Ada.Calendar;
    use Time;
    t : constant Ada.Calendar.Time := Clock;
  begin
    Set_Status(window, notify&hour(t)&':'&minute(t)&':'&second(t));
  end Notify;

  procedure set_stop(window : in out FFXIAlarm_Window_Type; stopped : in boolean) is
  begin
    if stopped then
      Text(window.startstop, GUI_Strings.Start);
      Text(window.Menu, command,
           Menu_Commands.MC_START,
           GUI_Strings.Start);
    else
      Text(window.startstop, GUI_Strings.Stop);
      Text(window.Menu, command,
           Menu_Commands.MC_START,
           GUI_Strings.Stop);
    end if;
  end set_stop;

  procedure on_edit (window : in out FFXIAlarm_Window_Type;
                     which  : in integer) is
  begin
    if Text(window.Key_Alarms(which).Edit) /= ""
    then State(window.Key_Alarms(which).Chk, Checked);
    else State(window.Key_Alarms(which).Chk, Unchecked); end if;
  end on_edit;

  function retrieve_config (window : in FFXIAlarm_Window_Type) return config_type is
    --str : string := GWindows.GStrings.To_String(Text(window.Key_Edit1));
    result : config_type;
  begin
    result.repeat    := to_boolean(State(window.Loop_Chk));
    result.tell      := to_boolean(State(window.Tell_Chk));
    result.linkshell := to_boolean(State(window.LS_Chk));
    result.party     := to_boolean(State(window.Party_Chk));
    result.say       := to_boolean(State(window.Say_Chk));
    result.shout     := to_boolean(State(window.Shout_Chk));

    for i in window.Key_Alarms'Range loop
      result.keywords(i).set := to_boolean(State(window.Key_Alarms(i).Chk));
      result.keywords(i).word    := Ada.Strings.Wide_Fixed.Head
        (Text(window.Key_Alarms(i).Edit), result.keywords(i).word'length);
      result.keywords(i).length  :=
        GWindows.GStrings.To_String(Text(window.Key_Alarms(i).Edit))'length;
    end loop;

    return result;
--    exception
--      when constraint_error =>
--        result.repeat    := False;
--        result.tell      := False;
--        result.linkshell := False;
--        result.party     := False;
--        result.say       := False;
--        result.shout     := False;
--        for i in 1..5 loop
--          result.keyword(i).keyword := False;
--          result.keyword(i).word    := Ada.Strings.Fixed.Head(str, result.keyword(i).word'length);
--          result.keyword(i).length  := 0;
--        end loop;
--        return result;
  end retrieve_config;

  procedure Minimize (window : in out FFXIAlarm_Window_Type) is
  begin
    Hide(Window.Top_Window);
    Tray_Icon(Window.Top_Window, Resources.Small_Icon, "FFXI Alarm");
  end Minimize;

  procedure Maximize (window : in out FFXIAlarm_Window_Type) is
  begin
    Show(Window.Top_Window);
    Restore(Window.Top_Window);
    Tray_Icon(Window.Top_Window,
              Resources.Small_Icon, Display => False);
  end Maximize;

  procedure Display_Tray_Menu (window : in out FFXIAlarm_Window_Type;
                               X : in integer;
                               Y : in integer) is
  begin
    if to_boolean(State(window.Tell_Chk)) then
      Check(Window.Menu, Command, Menu_Commands.MC_TELL, True);
    else
      Check(Window.Menu, Command, Menu_Commands.MC_TELL, False);
    end if;
    if to_boolean(State(window.LS_Chk)) then
      Check(Window.Menu, Command, Menu_Commands.MC_LINKSHELL, True);
    else
      Check(Window.Menu, Command, Menu_Commands.MC_LINKSHELL, False);
    end if;
    if to_boolean(State(window.Party_Chk)) then
      Check(Window.Menu, Command, Menu_Commands.MC_PARTY, True);
    else
      Check(Window.Menu, Command, Menu_Commands.MC_PARTY, False);
    end if;
    if to_boolean(State(window.Say_Chk)) then
      Check(Window.Menu, Command, Menu_Commands.MC_SAY, True);
    else
      Check(Window.Menu, Command, Menu_Commands.MC_SAY, False);
    end if;
    if to_boolean(State(window.Shout_Chk)) then
      Check(Window.Menu, Command, Menu_Commands.MC_SHOUT, True);
    else
      Check(Window.Menu, Command, Menu_Commands.MC_SHOUT, False);
    end if;
    if to_boolean(State(window.Loop_Chk)) then
      Check(Window.Menu, Command, Menu_Commands.MC_LOOP, True);
    else
      Check(Window.Menu, Command, Menu_Commands.MC_LOOP, False);
    end if;
    Set_Foreground_Window(Window.Top_Window);
    Display_Context_Menu(Window.Top_Window, Window.Menu, 0, X, Y);
  end Display_Tray_Menu;

  procedure Process_Menu_Command (window : in out FFXIAlarm_Window_Type;
                                  cmd    : in integer) is
  begin
    case cmd is
      when Menu_Commands.MC_TELL =>
        if to_boolean(State(window.Tell_Chk)) then
          State (window.Tell_chk, Unchecked);
        else
          State (window.Tell_chk, Checked);
        end if;
      when Menu_Commands.MC_LINKSHELL =>
        if to_boolean(State(window.LS_Chk)) then
          State (window.LS_chk, Unchecked);
        else
          State (window.LS_chk, Checked);
        end if;
      when Menu_Commands.MC_PARTY =>
        if to_boolean(State(window.Party_Chk)) then
          State (window.Party_chk, Unchecked);
        else
          State (window.Party_chk, Checked);
        end if;
      when Menu_Commands.MC_SAY =>
        if to_boolean(State(window.Say_Chk)) then
          State (window.Say_chk, Unchecked);
        else
          State (window.Say_chk, Checked);
        end if;
      when Menu_Commands.MC_SHOUT =>
        if to_boolean(State(window.Shout_Chk)) then
          State (window.Shout_chk, Unchecked);
        else
          State (window.Shout_chk, Checked);
        end if;
      when Menu_Commands.MC_LOOP =>
        if to_boolean(State(window.Loop_Chk)) then
          State (window.Loop_chk, Unchecked);
        else
          State (window.Loop_chk, Checked);
        end if;
      when others => null;
    end case;
  end Process_Menu_Command;

  procedure message_box (Window : in out FFXIAlarm_Window_Type;
                         msg : in string) is
  begin
    --Disable(Window.Top_Window);
    GWindows.Message_Boxes.Message_Box(Window.Window, "Error",
                                       GWindows.GStrings.To_GString_From_String(msg));
    --Enable(Window.Top_Window);
  end message_box;
end GUI;
